Custom Keyboard Reliability
The CustomKeyboard namespace provides a comprehensive API for building fully custom keyboard UIs in the Scripting app. It allows you to create JSX-based keyboards, insert or modify text, query input state, respond to user interaction, and control keyboard layout or navigation.
Script lifetime
Hiding the keyboard or switching to another keyboard ends its running script and closes its Rime sessions. Reopening the keyboard runs the configured default script again. Persist state that must survive between presentations, and create a fresh Rime session during each script startup. A failed switch between scripts leaves the previous script running.
1. Environment & Setup
Requirements
-
You must define your keyboard interface in a file named
**keyboard.tsx**inside your script project. -
The
CustomKeyboardAPI is only available in the keyboard extension environment. -
It is not available in App scripts, Intents (
intent.tsx), or Widgets (widget.tsx). -
You must enable the keyboard in iOS settings:
Then tap the Scripting Keyboard and enable Allow Full Access to unlock clipboard and network features.
2. Presentation
present(node: VirtualNode): void
Renders your custom keyboard UI using the given JSX node. This function must be called once in keyboard.tsx.
3. Text Input State
4. Input Traits
useTraits(): TextInputTraits
Hook to retrieve the current input traits (e.g., keyboard type, return key style). It automatically updates when textDidChange or selectionDidChange events occur.
traits: TextInputTraits
A snapshot of the traits at the last change. Prefer useTraits() in JSX components for reactivity.
Example fields:
keyboardType:'default','numberPad','emailAddress'...returnKeyType:'go','search','done'...autocapitalizationType:'none','sentences', etc.textContentType: semantic input hints like'username','oneTimeCode', etc.keyboardAppearance:'light','dark', etc.
5. Text Manipulation
insertText(text: string): void
Insert text at the current cursor position.
deleteBackward(): void
Delete one character before the cursor.
moveCursor(offset: number): void
Move the cursor by a number of characters. Negative = left; Positive = right.
setMarkedText(text, location, length): void
Mark a portion of inserted text (used in composition scenarios like Pinyin input).
unmarkText(): void
Clear any currently marked text.
6. Keyboard Behavior Control
dismiss(): void
Dismiss the keyboard view.
nextKeyboard(): void
Switch to the next system keyboard.
requestHeight(height: number): void
Request a new keyboard height in points. Recommended range is 216–360pt.
setHasDictationKey(value: boolean): void
Control whether the dictation (microphone) key is shown.
setToolbarVisible(visible: boolean): void
Show or hide the custom keyboard toolbar. Useful for debugging.
7. Navigation
allScripts: KeyboardScriptInfo[]
Lists all scripts that can run in the custom keyboard extension.
Each item contains:
switchToScript(scriptName: string, queryParameters?: Record<string, string>): Promise<void>
Dismisses the current keyboard script and runs another keyboard script by name.
The optional queryParameters object is exposed to the target script as Script.queryParameters.
nextScript(queryParameters?: Record<string, string>): Promise<void>
Dismisses the current keyboard script and runs the next available keyboard script.
The optional queryParameters object is exposed to the target script as Script.queryParameters.
dismissToHome(): void
Dismisses the currently active keyboard script and returns to the Scripting keyboard home screen (script list). Useful for letting users choose another script.
8. User Feedback
playInputClick(): void
Play the standard system keyboard click sound. Useful when simulating real key taps.
9. Event Listeners
addListener(event, callback): void
Register a listener for keyboard or text input changes.
removeListener(event, callback): void
Remove a specific listener.
removeAllListeners(event): void
Remove all listeners for a given event type.
10. Full Example
11. Best Practices
- Call
present()only once in yourkeyboard.tsxfile. - Use
requestHeight()to ensure appropriate layout on different screen sizes. - Prefer
useTraits()for reactive input context access in JSX. - Use
dismissToHome()instead ofdismiss()if you want to return to the script list. - Call
playInputClick()when simulating key taps for user feedback. - Always check for
hasTextbefore callingdeleteBackward().
